//Copyright 2010 Balazs Keri, Imre Keri
//
//This file is part of FireworksCreator.
//
//FireworksCreator is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//FireworksCreator is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with FireworksCreator.  If not, see <http://www.gnu.org/licenses/>.
//
#include <global.h>
#include <qstatemachine.h>
#include <qstate.h>
#include <QVBoxLayout>
#include "playerwindow.h"
#include "playercontrol.h"
#include "displayview.h"
//
SetDocTransition::SetDocTransition(DisplayView *view)
:
   QSignalTransition(view,SIGNAL(doc_changed())),
   view(view)
{
}
void SetDocTransition::onTransition(QEvent *event)
{
   //QSignalEvent *e=static_cast<QStateMachine::SignalEvent*>(event)->arguments.at(0).toObject();
   const Document *const doc=view->get_document();
   view->player_window->set_model(doc->get_root());
   view->player_control->set_range(0,doc->get_firework_length()*1000);
   view->player_control->set_current_time(view->player_window->get_current_time());
}
ClearDocTransition::ClearDocTransition(DisplayView *view)
:
   QSignalTransition(view,SIGNAL(doc_cleared())),
   view(view)
{
}
void ClearDocTransition::onTransition(QEvent *event)
{
   view->player_window->set_model(0);
}
//
//
DisplayView::DisplayView(QWidget *parent)
:
   QWidget(parent),
   player_window(new PlayerWindow()),
   player_control(new PlayerControl()),
   timer(new QTimer(this)),
   machine(0)
{
   timer->setInterval(time_update_interval);
   //
   QVBoxLayout *l=new QVBoxLayout();
   l->addWidget(player_window,1);
   l->addWidget(player_control);
   setLayout(l);
   //
   create_machine();
   machine->start();
   //
   connect(timer,SIGNAL(timeout()),this,SLOT(on_timer_timeout()));
   connect(player_control,SIGNAL(current_time_changed(unsigned int)),this,SLOT(on_player_current_time_changed(unsigned int)));
}
DisplayView::~DisplayView()
{
   delete machine;
}
//
void DisplayView::on_timer_timeout()
{
   unsigned int current_time=player_window->get_current_time()*1000;
   if(current_time>=player_control->get_stop_time())
   {
      if(player_control->get_looping())
      {
         current_time=player_control->get_start_time();
         player_window->set_current_time(current_time/1000.0);
      }
      else
      {
         player_control->set_playing(false);
         return;
      }
   }
   player_control->blockSignals(true);
   player_control->set_current_time(current_time);
   player_control->blockSignals(false);
}
void DisplayView::on_player_current_time_changed(unsigned int time)
{
   player_window->set_current_time(time/1000.0);
}
void DisplayView::on_player_start_time_changed(unsigned int)
{
}
void DisplayView::on_player_stop_time_changed(unsigned int)
{
}
//
void DisplayView::handle_set_attr_group()
{
   if(get_document()!=0)
   {
      emit doc_changed();
   }
   else
   {
      emit doc_cleared();
   }
}
void DisplayView::handle_post_primitive_group(const PrimitiveGroup &p_primitive_group)
{
   qDebug("DisplayView post_primitive_group");
   player_window->set_model(get_document()->get_root());
   player_control->set_range(0,get_document()->get_firework_length()*1000);
   player_control->set_current_time(player_window->get_current_time());
   //TODO check for changed length,...
   //emit signal and have transition in 'machine' instead?
}
void DisplayView::handle_attr_event(AttrEvent *event)
{
}
//
void DisplayView::create_machine()
{
   machine=new QStateMachine;
   QState *no_doc_state=new QState(machine);
   QState *doc_state=new QState(machine);
   QState *not_playing_state=new QState(doc_state);
   QState *playing_state=new QState(doc_state);
   //
   no_doc_state->assignProperty(player_control,"enabled",false);
   no_doc_state->assignProperty(player_window,"enabled",false);
   no_doc_state->assignProperty(timer,"active",false);
   SetDocTransition *st=new SetDocTransition(this);
   st->setTargetState(doc_state);
   no_doc_state->addTransition(st);
   //
   doc_state->assignProperty(player_control,"enabled",true);
   doc_state->assignProperty(player_window,"enabled",true);
   doc_state->setInitialState(not_playing_state);
   st=new SetDocTransition(this);
   st->setTargetState(doc_state);
   doc_state->addTransition(st);
   ClearDocTransition *ct=new ClearDocTransition(this);
   ct->setTargetState(no_doc_state);
   doc_state->addTransition(ct);
   st=new SetDocTransition(this);
   st->setTargetState(doc_state);
   doc_state->addTransition(st);
   //
   not_playing_state->assignProperty(player_control,"isPlaying",false);
   not_playing_state->assignProperty(player_window,"isPlaying",false);
   BoolCheckTransition *bct=new BoolCheckTransition(0,true,player_control,SIGNAL(playing_changed(bool)));
   bct->setTargetState(playing_state);
   not_playing_state->addTransition(bct);
   //
   playing_state->assignProperty(player_control,"isPlaying",true);
   playing_state->assignProperty(player_window,"isPlaying",true);
   connect(playing_state,SIGNAL(entered()),timer,SLOT(start()));
   connect(playing_state,SIGNAL(exited()),timer,SLOT(stop()));
   bct=new BoolCheckTransition(0,false,player_control,SIGNAL(playing_changed(bool)));
   bct->setTargetState(not_playing_state);
   playing_state->addTransition(bct);
   //
   machine->setInitialState(no_doc_state);
}
